<?php

/**
 * The PDO adaptor for prepared statements.
 * @package Nina
 * @author John Main <john@thedaddy.org>, Chris Corbyn
 */
class Nina_Db_Driver_Statement_Pdo extends Nina_Db_Driver_Statement
{
	/**
	 * The PDO database instance.
	 * @var PDO
	 */
	protected $pdo;
	/**
	 * The PDOStatement instance.
	 * @var PDOStatement
	 */
	protected $statement;
	/**
	 * Bound references.
	 * @var array
	 */
	protected $vars = array();
	/**
	 * Keeps track of the last integer index for PDO statements.
	 * @var int
	 */
	protected $numIndexedVars = 0;
	
	/**
	 * Set the PDO instance.
	 * @param PDO $pdo
	 */
	public function setPdo(PDO $pdo) {
		$this->pdo = $pdo;
	}

	/**
	 * Get the PDO instance.
	 * @return PDO
	 */
	public function getPdo() {
		return $this->pdo;
	}

	/**
	 * Set the PDOStatement instance.
	 * @param PDOStatement $stmt
	 */
	protected function setStatement(PDOStatement $stmt) {
		$this->statement = $stmt;
	}

	/**
	 * Get the PDO statement.
	 * @return PDOStatement
	 */
	protected function getStatement() {
		return $this->statement;
	}

	/**
	 * Set the SQL being executed.
	 * @param string $sql SQL
	 */
	public function setSql($sql) {
		$this->sql = $sql;
		$stmt = $this->getPdo()->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
		if (!$stmt) $stmt = $this->getPdo()->prepare($sql);
		if (!$stmt) return false;
		$this->setStatement($stmt);
	}

	/**
	 * Get the SQL being executed.
	 * @return string
	 */
	public function getSql() {
		return $this->sql;
	}

	/**
	 * Bind a value to the prepared statement (this isn't really what happens with the mysql_..() functions though).
	 * @param Array $vars Variables to bind.
	 */
	public function bind(Array $vars) {
		if (!$this->getStatement()) return;
		
		foreach ($vars as $k => &$v) {
			if (!is_int($k)) {
				$k = ":" . $k;
			}
			else
			{
				$this->numIndexedVars++;
				$k = $this->numIndexedVars;
			}
			$this->vars[$k] =& $v;
			$this->getStatement()->bindParam($k, $this->vars[$k]);
		}
	}

	/**
	 * Execute the statement and get the result.
	 * @return Nina_Db_Driver_Result
	 */
	public function execute() {
		if (!$this->getStatement()
			|| !$this->getStatement()->execute()) {
			$errmsg = "PDO SQL statement failed to execute. [ " .
			$this->getSql() . " ]";
			if ($this->vars) {
				$errmsg .= " with bound variables [ " . implode(", ", $this->vars) . " ]";
			}
			$errmsg .= ". ERROR: " . $this->getDb()->lastError() . ".";
			throw new Nina_Exception_Db_Driver($errmsg);
		}
		$rs = new Nina_Db_Driver_Result_Pdo();
		$rs->setPdo($this->getPdo());
		$rs->setPdoResult($this->getStatement());
		return $rs;
	}
}
